/*
 *  Author: Gary Kelly, gkelly2008@my.fit.edu
 *  Author: John Stevens, jstevens@fit.edu
 *  Class:  CSE 4232 - Network Programming
 *  Program: SQlite database synchronization main program
 */


#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <sqlite3.h>

//Global variables
sem_t semDB;
sem_t semIO;
sqlite3* db;
int port = 0;


//Include the thread functions
#include "user.cpp"
#include "server.cpp"


//temporary functions
void* clientRun (void*) {};

//function to close all open handles
void cleanup ();

using namespace std;

int main (int argc, char* argv[]) {
	int rc = 0;
	string dbFileName = "";
	pthread_t server, user, client;
	
	//make sure we have all of the required arguments
	if (argc != 5) {
		cerr << "Usage: myP2P [arguments]..." << endl;
		cerr << "Run the database P2P application."  << endl;
		cerr << "  -d\tspecify the database file" << endl;
		cerr << "  -p\tspecify the port to listen on" << endl;
		return 1;
	}

	//get the command line arguments
	if (strcmp (argv[1], "-d") == 0) {
		dbFileName = argv[2];
	} else if (strcmp (argv[1], "-p") == 0) {
		port = atoi (argv[2]);
	}
	//we don't care which order they are in
	if (strcmp (argv[3], "-d") == 0) {
		dbFileName = argv[4];
	} else if (strcmp (argv[3], "-p") == 0) {
		port = atoi (argv[4]);
	}

	// attempt to open the database file
	if (sqlite3_open (dbFileName.c_str (), &db) != 0) {
		cerr << "sqlite3_open error: " << sqlite3_errmsg(db);
		sqlite3_close (db);
		return 1;
	}

	cout << "Database file: " << dbFileName << endl;
	cout << "Port: " << port << endl;
	
	//Initialization
	sem_init (&semDB, 0, 1);
	sem_init (&semIO, 0, 1);
	
	//Create the threads
	if ( (rc = pthread_create (&user, NULL, &userRun, NULL)) != 0) {
		cerr << "Create thread failed for user thread with error: " << strerror (rc) << endl;
		cleanup ();
		return 1;
	}

	if ( (rc = pthread_create (&server, NULL, &serverRun, NULL)) != 0) {
		cerr << "Create thread failed for server thread with error: " << strerror (rc) << endl;
		cleanup ();
		return 1;
	}

	if ( (rc = pthread_create (&client, NULL, &clientRun, NULL)) != 0) {
		cerr << "Create thread failed for client with error: " << strerror (rc) << endl;
		cleanup ();
		return 1;
	}
	
	cout << "server: " << server << endl;

	//Wait for them to finish
	if ( (rc = pthread_join (user, NULL)) != 0) {
		cerr << "Failed to join user thread with error: " << strerror (rc) << endl;
		cleanup ();
		return 1;
	}

	if ( (rc = pthread_join (server, NULL)) != 0) {
		cerr << "Failed to join server thread with error: " << strerror (rc) << endl;
		cleanup ();
		return 1;
	}

	if ( (rc = pthread_join (client, NULL)) != 0) {
		cerr << "Failed to join client thread with error: " << strerror (rc) << endl;
		cleanup ();
		return 1;
	}

	//Cleanup
	cleanup ();
	
	return 0;	
}

//Function to close all open handles
void cleanup () {
	sqlite3_close (db);
	sem_destroy (&semDB);
	sem_destroy (&semIO);
}
